package org.dsapr.codegen.processor.converter;

import com.google.auto.service.AutoService;
import com.squareup.javapoet.*;
import org.dsapr.codegen.common.AutoGenerateConverter;
import org.dsapr.codegen.common.BaseGenerateProcessor;
import org.dsapr.codegen.common.CodeGenerateProcessor;
import org.dsapr.codegen.model.NameContext;
import org.dsapr.codegen.utils.NameUtil;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.TypeElement;
import java.io.File;
import java.lang.annotation.Annotation;
import java.nio.file.Path;
import java.nio.file.Paths;

import static javax.lang.model.element.Modifier.*;

@AutoService(value = CodeGenerateProcessor.class)
public class ConverterAutoGenerateProcessor extends BaseGenerateProcessor {
	private static final String CODEGEN_INFO = buildMessage();

	@Override
	public void generateClass(TypeElement typeElement, RoundEnvironment roundEnvironment) throws Exception {
		NameContext context = NameContext.builder().build(typeElement);
		String className = context.getConverterName();
		String packageName = context.getConverterPackageName();

		AnnotationSpec convertAnno = AnnotationSpec.builder(Mapper.class).build();

		TypeSpec.Builder typeSpecBuilder = TypeSpec.interfaceBuilder(className)
				.addAnnotation(convertAnno)
				.addModifiers(PUBLIC)
				.addJavadoc(CODEGEN_INFO);

		FieldSpec field = FieldSpec.builder(ClassName.get(packageName, className), "INSTANCE")
				.addModifiers(PUBLIC, STATIC, FINAL)
				.initializer("$T.getMapper($T.class)",
						Mappers.class, ClassName.get(packageName, className)).build();

		typeSpecBuilder.addField(field);

		// add method entityToVo
		if (context.getControllerPackageName() != null) {
			typeSpecBuilder.addMethod(getEntityToVoMethodSpec(context));
		}

		Path srcPath = Paths.get(typeElement.getAnnotation(AutoGenerateConverter.class).sourcePath());
		File srcAbsoluteFile = srcPath.toFile().getAbsoluteFile();
		if (srcAbsoluteFile.exists()) {
			File sourceFile = new File(srcAbsoluteFile.getAbsolutePath(), context.getControllerClassName() + ".java");
			if (!sourceFile.exists()) {
				writeJavaFile(getPackage(typeElement), typeSpecBuilder.build(), srcAbsoluteFile.getAbsolutePath());
			}
		}
	}

	private MethodSpec getEntityToVoMethodSpec(NameContext c) {
		return MethodSpec.methodBuilder("toVo")
				.addModifiers(PUBLIC, ABSTRACT)
				.returns(ClassName.get(c.getVoPackageName(), c.getVoClassName()))
				.addParameter(ClassName.get(c.getEntityPackageName(), c.getClassName()), NameUtil.toCamelCase(c.getClassName()))
				.build();
	}

	@Override
	public Class<? extends Annotation> getAnnotation() {
		return AutoGenerateConverter.class;
	}

	@Override
	public String getPackage(TypeElement typeElement) {
		return typeElement.getAnnotation(AutoGenerateConverter.class).packageName();
	}
}
